package chat;

import javax.swing.*;
import javax.swing.border.TitledBorder;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.util.*;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;

public class ChatClient extends JFrame {
    // ================== 共享成员变量 ==================
    private static final String SERVER_HOST = "localhost";
    private static final int SERVER_PORT = 8888;
    private static final int MAX_WINDOWS = 10;

    // UI 组件
    private JList<String> groupList;
    private DefaultListModel<String> groupListModel;
    private JList<String> memberList;
    private DefaultListModel<String> memberListModel;
    private JTextField usernameField;
    private JButton loginBtn;
    private JList<String> userList;
    private DefaultListModel<String> userListModel;
    private JTabbedPane chatTabs;

    // 数据状态
    private Map<String, ChatPanel> chatPanels = new ConcurrentHashMap<>();
    private Map<String, Set<String>> groupMembers = new ConcurrentHashMap<>();
    private Map<String, Set<String>> subgroupMembers = new ConcurrentHashMap<>();
    private Map<String, String> userSubgroups = new ConcurrentHashMap<>();
    private Map<String, String> userGroupSubgroup = new ConcurrentHashMap<>();
    private Map<String, String> subgroupToGroupMap = new ConcurrentHashMap<>();
    private String currentSubgroupId;
    private Socket socket;
    private ObjectOutputStream output;
    private ObjectInputStream input;
    private String username;
    private int openWindowCount = 0;
    private String lastLoginTime = "";

    // 语音相关
    private JButton voiceChatBtn;
    private JButton conferenceBtn;
    private JDialog voiceControlDialog;
    private JLabel voiceStatusLabel;
    private boolean isVoiceActive = false;
    private String currentVoiceTarget = "";

    // 管理器实例
    private final LoginManager loginManager = new LoginManager();
    private final MainPanelManager mainPanelManager = new MainPanelManager();
    private final GroupManager groupManager = new GroupManager();
    private final MemberListManager memberListManager = new MemberListManager();
    private final VoiceManager voiceManager = new VoiceManager();
    private final FileTransferManager fileTransferManager = new FileTransferManager();
    private final MessageHandler messageHandler = new MessageHandler();

    public ChatClient() {
        initializeGUI();
    }

    private void initializeGUI() {
        setTitle("网络聊天室");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(1100, 700);
        setLocationRelativeTo(null);

        // 创建各个面板
        JPanel loginPanel = loginManager.createLoginPanel();
        JPanel mainPanel = mainPanelManager.createMainPanel();
        JPanel memberPanel = memberListManager.createMemberListPanel();
        JPanel voicePanel = voiceManager.createVoicePanel();

        // 布局
        setLayout(new BorderLayout());
        add(loginPanel, BorderLayout.NORTH);
        add(mainPanel, BorderLayout.CENTER);
        add(memberPanel, BorderLayout.EAST);
        add(voicePanel, BorderLayout.SOUTH);

        // 窗口关闭事件
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                loginManager.disconnect();
                System.exit(0);
            }
        });
    }

    // ================== 登录管理 ==================
    private class LoginManager {
        public JPanel createLoginPanel() {
            JPanel panel = new JPanel(new FlowLayout());
            panel.setBorder(new TitledBorder("登录"));

            panel.add(new JLabel("用户名:"));
            usernameField = new JTextField(15);
            panel.add(usernameField);

            loginBtn = new JButton("登录");
            loginBtn.addActionListener(e -> {
                if (loginBtn.getText().equals("登录")) {
                    connect();
                } else {
                    disconnect();
                }
            });
            panel.add(loginBtn);

            usernameField.addActionListener(e -> {
                if (loginBtn.getText().equals("登录")) {
                    connect();
                }
            });

            return panel;
        }

        private void connect() {
            String user = usernameField.getText().trim();
            if (user.isEmpty()) {
                JOptionPane.showMessageDialog(ChatClient.this, "请输入用户名");
                return;
            }

            try {
                socket = new Socket(SERVER_HOST, SERVER_PORT);
                output = new ObjectOutputStream(socket.getOutputStream());
                input = new ObjectInputStream(socket.getInputStream());

                username = user;
                lastLoginTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

                VoiceChatManager.initialize(username);
                int voicePort = VoiceChatManager.getVoicePort();
                if (voicePort <= 0) {
                    throw new IOException("获取语音端口失败");
                }

                String localIP = InetAddress.getLocalHost().getHostAddress();

                groupManager.loadGroupList();

                Message loginMsg = new Message(Message.Type.LOGIN, username, "");
                output.writeObject(loginMsg);

                Message ipMsg = new Message(Message.Type.IP_UPDATE, username, "");
                ipMsg.setIpAddress(localIP);
                ipMsg.setVoicePort(voicePort);
                output.writeObject(ipMsg);

                VoiceChatManager.updateUserIP(username, localIP, voicePort);
                new Thread(ChatClient.this::receiveMessages).start();

                loginBtn.setText("登出");
                usernameField.setEnabled(false);
                JOptionPane.showMessageDialog(ChatClient.this, "连接成功！");

            } catch (IOException e) {
                JOptionPane.showMessageDialog(ChatClient.this, "连接服务器失败: " + e.getMessage());
            }
        }

        private void disconnect() {
            if (isVoiceActive) {
                voiceManager.endVoiceChat();
            }
            VoiceChatManager.cleanup(username);

            try {
                if (output != null) {
                    Message logoutMsg = new Message(Message.Type.LOGOUT, username, "");
                    output.writeObject(logoutMsg);
                }
                if (socket != null) socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

            groupManager.saveGroupList();
            loginBtn.setText("登录");
            usernameField.setEnabled(true);
            userListModel.clear();
            userGroupSubgroup.clear();
            subgroupToGroupMap.clear();
            chatTabs.removeAll();
            chatPanels.clear();
            openWindowCount = 0;
            username = null;
        }
    }

    // ================== 群组管理 ==================
    private class GroupManager {
        public JPanel createGroupPanel() {
            JPanel panel = new JPanel(new FlowLayout());
            panel.setBorder(new TitledBorder("群组操作"));

            JTextField groupField = new JTextField(15);
            JButton joinGroupBtn = new JButton("加入群组");
            JButton fileBtn = new JButton("发送群文件");

            joinGroupBtn.addActionListener(e -> {
                String groupName = groupField.getText().trim();
                if (!groupName.isEmpty()) {
                    openGroupChat(groupName);
                    groupField.setText("");
                }
            });

            fileBtn.addActionListener(e -> {
                String groupName = groupField.getText().trim();
                if (!groupName.isEmpty()) {
                    fileTransferManager.sendGroupFile(groupName);
                } else {
                    JOptionPane.showMessageDialog(ChatClient.this, "请先输入群组名");
                }
            });

            groupField.addActionListener(e -> {
                String groupName = groupField.getText().trim();
                if (!groupName.isEmpty()) {
                    openGroupChat(groupName);
                    groupField.setText("");
                }
            });

            panel.add(new JLabel("群组名:"));
            panel.add(groupField);
            panel.add(joinGroupBtn);
            panel.add(fileBtn);

            return panel;
        }

        public void openGroupChat(String groupName) {
            if (openWindowCount >= MAX_WINDOWS) {
                JOptionPane.showMessageDialog(ChatClient.this, "最多只能打开" + MAX_WINDOWS + "个聊天窗口");
                return;
            }

            String tabId = "group_" + groupName;
            if (!chatPanels.containsKey(tabId)) {
                ChatPanel panel = new ChatPanel(groupName, true);
                chatPanels.put(tabId, panel);
                chatTabs.addTab("群:" + groupName, panel);

                int index = chatTabs.getTabCount() - 1;
                chatTabs.setTabComponentAt(index, createTabComponent("群:" + groupName, tabId));

                openWindowCount++;

                try {
                    Message joinMsg = new Message(Message.Type.GROUP_CHAT, username, "加入了群组");
                    joinMsg.setGroup(groupName);
                    output.writeObject(joinMsg);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            for (int i = 0; i < chatTabs.getTabCount(); i++) {
                Component tabComponent = chatTabs.getTabComponentAt(i);
                if (tabComponent instanceof JPanel) {
                    JLabel label = (JLabel) ((JPanel) tabComponent).getComponent(0);
                    if (label.getText().equals("群:" + groupName)) {
                        chatTabs.setSelectedIndex(i);
                        break;
                    }
                }
            }
        }

        private JPanel createTabComponent(String title, String tabId) {
            JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
            panel.setOpaque(false);

            JLabel label = new JLabel(title);
            JButton closeBtn = new JButton("×");
            closeBtn.setPreferredSize(new Dimension(17, 17));
            closeBtn.setMargin(new Insets(0, 0, 0, 0));
            closeBtn.setFont(new Font("Dialog", Font.PLAIN, 12));
            closeBtn.addActionListener(e -> ChatClient.this.closeTab(tabId));

            panel.add(label);
            panel.add(Box.createHorizontalStrut(5));
            panel.add(closeBtn);

            return panel;
        }

        public void saveGroupList() {
            try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("group_list_" + username + ".ser"))) {
                oos.writeObject(groupListModel);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        public void loadGroupList() {
            try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("group_list_" + username + ".ser"))) {
                groupListModel = (DefaultListModel<String>) ois.readObject();
                groupList.setModel(groupListModel);
            } catch (IOException | ClassNotFoundException e) {
                groupListModel = new DefaultListModel<>();
                groupList.setModel(groupListModel);
            }
        }
    }

    // ================== 成员列表管理 ==================
    private class MemberListManager {
        public JPanel createMemberListPanel() {
            JPanel panel = new JPanel(new BorderLayout());
            panel.setBorder(new TitledBorder("群成员(按Ctrl多选)"));
            panel.setPreferredSize(new Dimension(200, 0));

            memberListModel = new DefaultListModel<>();
            memberList = new JList<>(memberListModel);
            memberList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
            JScrollPane scrollPane = new JScrollPane(memberList);

            JPanel buttonPanel = new JPanel(new GridLayout(2, 1));
            JButton createSubgroupBtn = new JButton("创建小组");
            JButton leaveSubgroupBtn = new JButton("离开小组");

            createSubgroupBtn.addActionListener(e -> createSubgroup());
            leaveSubgroupBtn.addActionListener(e -> leaveSubgroup());

            buttonPanel.add(createSubgroupBtn);
            buttonPanel.add(leaveSubgroupBtn);

            panel.add(scrollPane, BorderLayout.CENTER);
            panel.add(buttonPanel, BorderLayout.SOUTH);

            memberList.addMouseListener(new java.awt.event.MouseAdapter() {
                @Override
                public void mouseClicked(java.awt.event.MouseEvent e) {
                    if (e.getClickCount() == 2) {
                        String selectedMember = memberList.getSelectedValue();
                        if (selectedMember != null && !selectedMember.equals(username)) {
                            ChatClient.this.openPrivateChat(selectedMember);
                        }
                    }
                }
            });

            return panel;
        }

        private void createSubgroup() {
            if (chatTabs.getSelectedComponent() == null) return;

            ChatPanel currentPanel = (ChatPanel) chatTabs.getSelectedComponent();
            if (!currentPanel.isGroup()) {
                JOptionPane.showMessageDialog(ChatClient.this, "请在群聊中创建小组");
                return;
            }

            String group = currentPanel.getChatTarget();
            Set<String> selectedMembers = new HashSet<>(memberList.getSelectedValuesList());

            if (selectedMembers.isEmpty()) {
                JOptionPane.showMessageDialog(ChatClient.this, "请选择至少一名成员");
                return;
            }

            selectedMembers.remove(username);

            if (selectedMembers.isEmpty()) {
                JOptionPane.showMessageDialog(ChatClient.this, "请选择其他成员");
                return;
            }

            String groupUserKey = group + ":" + username;
            if (userGroupSubgroup.containsKey(groupUserKey)) {
                JOptionPane.showMessageDialog(ChatClient.this, "您已在本群加入其他小组，无法创建新小组");
                return;
            }

            String subgroupId = UUID.randomUUID().toString().substring(0, 8);
            for (String member : selectedMembers) {
                sendSubgroupInvite(group, subgroupId, member);
            }

            openSubgroupChat(subgroupId);

            currentSubgroupId = subgroupId;
            userSubgroups.put(username, subgroupId);
            subgroupMembers.computeIfAbsent(subgroupId, k -> new HashSet<>()).add(username);
            userGroupSubgroup.put(groupUserKey, subgroupId);
            subgroupToGroupMap.put(subgroupId, group);
        }

        private void sendSubgroupInvite(String group, String subgroupId, String member) {
            try {
                Message invite = new Message(Message.Type.SUBGROUP_INVITE, username,
                        "邀请您加入小组讨论: " + subgroupId);
                invite.setGroup(group);
                invite.setReceiver(member);
                invite.setSubgroupId(subgroupId);
                output.writeObject(invite);
            } catch (IOException ex) {
                JOptionPane.showMessageDialog(ChatClient.this, "邀请发送失败: " + ex.getMessage());
            }
        }

        private void leaveSubgroup() {
            if (currentSubgroupId == null) {
                JOptionPane.showMessageDialog(ChatClient.this, "您当前没有加入任何小组");
                return;
            }

            try {
                Message leaveMsg = new Message(Message.Type.SUBGROUP_LEAVE, username, "离开了小组");
                leaveMsg.setSubgroupId(currentSubgroupId);
                output.writeObject(leaveMsg);

                closeSubgroupChat(currentSubgroupId);
                String group = subgroupToGroupMap.get(currentSubgroupId);
                if (group != null) {
                    String groupUserKey = group + ":" + username;
                    userGroupSubgroup.remove(groupUserKey);
                }
                userSubgroups.remove(username);
                currentSubgroupId = null;
                JOptionPane.showMessageDialog(ChatClient.this, "已离开小组");
            } catch (IOException ex) {
                JOptionPane.showMessageDialog(ChatClient.this, "离开小组失败: " + ex.getMessage());
            }
        }

        private void openSubgroupChat(String subgroupId) {
            String tabId = "subgroup_" + subgroupId;
            if (!chatPanels.containsKey(tabId)) {
                ChatPanel panel = new ChatPanel(subgroupId, false, true);
                chatPanels.put(tabId, panel);
                chatTabs.addTab("小组:" + subgroupId, panel);

                int index = chatTabs.getTabCount() - 1;
                chatTabs.setTabComponentAt(index, ChatClient.this.createTabComponent("小组:" + subgroupId, tabId));

                openWindowCount++;
            }

            for (int i = 0; i < chatTabs.getTabCount(); i++) {
                Component tabComponent = chatTabs.getTabComponentAt(i);
                if (tabComponent instanceof JPanel) {
                    JLabel label = (JLabel) ((JPanel) tabComponent).getComponent(0);
                    if (label.getText().equals("小组:" + subgroupId)) {
                        chatTabs.setSelectedIndex(i);
                        break;
                    }
                }
            }
        }

        private void closeSubgroupChat(String subgroupId) {
            String tabId = "subgroup_" + subgroupId;
            ChatPanel panel = chatPanels.remove(tabId);
            if (panel != null) {
                for (int i = 0; i < chatTabs.getTabCount(); i++) {
                    if (chatTabs.getComponentAt(i) == panel) {
                        chatTabs.removeTabAt(i);
                        openWindowCount--;
                        break;
                    }
                }
            }
        }
    }

    // ================== 语音管理 ==================
    private class VoiceManager {
        public JPanel createVoicePanel() {
            JPanel panel = new JPanel(new FlowLayout());
            panel.setBorder(new TitledBorder("语音聊天"));

            voiceChatBtn = new JButton("一对一语音");
            conferenceBtn = new JButton("创建会议");

            voiceChatBtn.addActionListener(e -> startVoiceChat());
            conferenceBtn.addActionListener(e -> createConference());

            panel.add(voiceChatBtn);
            panel.add(conferenceBtn);

            initVoiceControlDialog();

            return panel;
        }

        private void initVoiceControlDialog() {
            voiceControlDialog = new JDialog(ChatClient.this, "语音控制", false);
            voiceControlDialog.setLayout(new BorderLayout());
            voiceControlDialog.setSize(300, 150);

            JPanel controlPanel = new JPanel(new FlowLayout());
            voiceStatusLabel = new JLabel("语音状态: 未连接");

            JButton endCallBtn = new JButton("结束通话");
            endCallBtn.addActionListener(e -> endVoiceChat());

            controlPanel.add(voiceStatusLabel);
            controlPanel.add(endCallBtn);

            voiceControlDialog.add(controlPanel, BorderLayout.CENTER);
            voiceControlDialog.addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosing(WindowEvent e) {
                    voiceControlDialog.setVisible(false);
                }
            });
        }

        private void startVoiceChat() {
            if (!isLoggedIn()) {
                JOptionPane.showMessageDialog(ChatClient.this, "请先登录");
                return;
            }

            String[] onlineUsers = new String[userListModel.size()];
            for (int i = 0; i < userListModel.size(); i++) {
                onlineUsers[i] = userListModel.getElementAt(i);
            }

            String targetUser = (String) JOptionPane.showInputDialog(
                    ChatClient.this,
                    "选择语音聊天对象:",
                    "一对一语音",
                    JOptionPane.PLAIN_MESSAGE,
                    null,
                    onlineUsers,
                    null);

            if (targetUser != null && !targetUser.equals(username)) {
                currentVoiceTarget = targetUser;
                isVoiceActive = true;

                VoiceChatManager.initialize(username);

                if (VoiceChatManager.startVoiceChat(targetUser)) {
                    voiceStatusLabel.setText("语音状态: 与 " + targetUser + " 通话中");
                    voiceControlDialog.setVisible(true);

                    try {
                        Message voiceInvite = new Message(Message.Type.PRIVATE_CHAT,
                                username, "[语音邀请] 正在请求语音聊天");
                        voiceInvite.setReceiver(targetUser);
                        output.writeObject(voiceInvite);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                } else {
                    JOptionPane.showMessageDialog(ChatClient.this, "语音聊天启动失败");
                    isVoiceActive = false;
                }
            } else if (targetUser != null && targetUser.equals(username)) {
                JOptionPane.showMessageDialog(ChatClient.this, "不能与自己进行语音通话");
            }
        }

        private void createConference() {
            if (!isLoggedIn()) {
                JOptionPane.showMessageDialog(ChatClient.this, "请先登录");
                return;
            }

            JDialog participantDialog = new JDialog(ChatClient.this, "选择会议参与者", true);
            participantDialog.setLayout(new BorderLayout());
            participantDialog.setSize(450, 450);

            JList<String> userList = new JList<>(userListModel);
            userList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
            userList.setCellRenderer(new DefaultListCellRenderer() {
                @Override
                public Component getListCellRendererComponent(JList<?> list, Object value,
                                                              int index, boolean isSelected, boolean cellHasFocus) {
                    Component c = super.getListCellRendererComponent(list, value, index,
                            isSelected, cellHasFocus);
                    if (value.equals(username)) {
                        setText("[我] " + value);
                        setForeground(Color.GRAY);
                    }
                    return c;
                }
            });

            JScrollPane scrollPane = new JScrollPane(userList);

            JLabel selectionLabel = new JLabel("已选择: 0 位用户");
            userList.addListSelectionListener(e -> {
                if (!e.getValueIsAdjusting()) {
                    int count = userList.getSelectedIndices().length;
                    selectionLabel.setText("已选择: " + count + " 位用户");
                }
            });

            JPanel topPanel = new JPanel(new BorderLayout());
            topPanel.add(selectionLabel, BorderLayout.WEST);
            topPanel.add(new JLabel("在线用户 (按住Ctrl或Shift键可多选)"), BorderLayout.CENTER);

            participantDialog.add(topPanel, BorderLayout.NORTH);
            participantDialog.add(scrollPane, BorderLayout.CENTER);

            JPanel buttonPanel = new JPanel(new FlowLayout());
            JButton createBtn = new JButton("创建会议");
            JButton cancelBtn = new JButton("取消");

            createBtn.addActionListener(e -> {
                List<String> selectedUsers = userList.getSelectedValuesList();
                if (selectedUsers.isEmpty()) {
                    JOptionPane.showMessageDialog(ChatClient.this, "请至少选择一位参与者");
                    return;
                }

                if (selectedUsers.contains(username)) {
                    selectedUsers.remove(username);
                    JOptionPane.showMessageDialog(ChatClient.this, "已自动移除您自己");
                }

                String roomId = VoiceChatManager.createConferenceRoom(username);

                for (String user : selectedUsers) {
                    VoiceChatManager.joinConferenceRoom(roomId, user);
                    try {
                        Message confInvite = new Message(Message.Type.PRIVATE_CHAT,
                                username, "[会议邀请] 邀请您加入语音会议，房间ID: " + roomId);
                        confInvite.setReceiver(user);
                        output.writeObject(confInvite);
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                }

                if (VoiceChatManager.joinConferenceRoom(roomId, username)) {
                    isVoiceActive = true;
                    voiceStatusLabel.setText("语音状态: 会议中 (房间ID: " + roomId + ")");
                    voiceControlDialog.setVisible(true);
                }

                participantDialog.dispose();
            });

            cancelBtn.addActionListener(e -> participantDialog.dispose());
            buttonPanel.add(createBtn);
            buttonPanel.add(cancelBtn);

            participantDialog.add(buttonPanel, BorderLayout.SOUTH);
            participantDialog.setVisible(true);
        }

        private void endVoiceChat() {
            if (isVoiceActive) {
                VoiceChatManager.endVoiceChat();
                isVoiceActive = false;
                voiceControlDialog.setVisible(false);
                if (!currentVoiceTarget.isEmpty()) {
                    try {
                        Message voiceEnd = new Message(Message.Type.PRIVATE_CHAT,
                                username, "[语音结束] 语音聊天已结束");
                        voiceEnd.setReceiver(currentVoiceTarget);
                        output.writeObject(voiceEnd);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    currentVoiceTarget = "";
                }
            }
        }

        private boolean isLoggedIn() {
            return username != null && !username.isEmpty();
        }
    }

    // ================== 文件传输管理 ==================
    private class FileTransferManager {
        public void sendGroupFile(String groupName) {
            JFileChooser fileChooser = new JFileChooser();
            if (fileChooser.showOpenDialog(ChatClient.this) == JFileChooser.APPROVE_OPTION) {
                File file = fileChooser.getSelectedFile();
                if (file.length() > 10 * 1024 * 1024) {
                    JOptionPane.showMessageDialog(ChatClient.this, "文件大小不能超过10MB");
                    return;
                }

                try {
                    byte[] fileData = readFileData(file);
                    Message fileMsg = new Message(Message.Type.GROUP_FILE, username, "发送了群文件");
                    fileMsg.setGroup(groupName);
                    fileMsg.setFileName(file.getName());
                    fileMsg.setFileData(fileData);
                    output.writeObject(fileMsg);

                    JOptionPane.showMessageDialog(ChatClient.this, "群文件发送成功");
                } catch (IOException e) {
                    JOptionPane.showMessageDialog(ChatClient.this, "文件发送失败: " + e.getMessage());
                }
            }
        }

        private byte[] readFileData(File file) throws IOException {
            try (FileInputStream fis = new FileInputStream(file);
                 ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
                byte[] buffer = new byte[1024];
                int bytesRead;
                while ((bytesRead = fis.read(buffer)) != -1) {
                    baos.write(buffer, 0, bytesRead);
                }
                return baos.toByteArray();
            }
        }

        public void saveFile(String fileName, byte[] fileData) {
            JFileChooser fileChooser = new JFileChooser();
            fileChooser.setSelectedFile(new File(fileName));
            if (fileChooser.showSaveDialog(ChatClient.this) == JFileChooser.APPROVE_OPTION) {
                File file = fileChooser.getSelectedFile();
                try (FileOutputStream fos = new FileOutputStream(file)) {
                    fos.write(fileData);
                    JOptionPane.showMessageDialog(ChatClient.this, "文件保存成功: " + file.getAbsolutePath());
                } catch (IOException e) {
                    JOptionPane.showMessageDialog(ChatClient.this, "文件保存失败: " + e.getMessage());
                }
            }
        }

        public void handleFileTransfer(Message message) {
            int option = JOptionPane.showConfirmDialog(ChatClient.this,
                    "收到来自 " + message.getSender() + " 的文件: " + message.getFileName() +
                            "\n文件大小: " + (message.getFileData().length / 1024) + " KB\n是否接收?",
                    "文件传输", JOptionPane.YES_NO_OPTION);

            if (option == JOptionPane.YES_OPTION) {
                saveFile(message.getFileName(), message.getFileData());
            }
        }

        public void handleGroupFile(Message message) {
            if (message.getSender().equals(username)) {
                return;
            }
            String group = message.getGroup();
            String sender = message.getSender();
            String fileName = message.getFileName();
            byte[] fileData = message.getFileData();

            int option = JOptionPane.showConfirmDialog(ChatClient.this,
                    sender + " 在群聊 " + group + " 中发送了文件: " + fileName + "，是否接收？",
                    "文件接收", JOptionPane.YES_NO_OPTION);
            if (option == JOptionPane.YES_OPTION) {
                try {
                    JFileChooser fileChooser = new JFileChooser();
                    fileChooser.setSelectedFile(new File(fileName));
                    int returnValue = fileChooser.showSaveDialog(ChatClient.this);
                    if (returnValue == JFileChooser.APPROVE_OPTION) {
                        File saveFile = fileChooser.getSelectedFile();
                        try (FileOutputStream fos = new FileOutputStream(saveFile)) {
                            fos.write(fileData);
                            JOptionPane.showMessageDialog(ChatClient.this, "文件保存成功: " + saveFile.getAbsolutePath());
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    JOptionPane.showMessageDialog(ChatClient.this, "文件保存失败: " + e.getMessage());
                }
            }
        }
    }

    // ================== 消息处理 ==================
    private class MessageHandler {
        public void handleMessage(Message message) {
            switch (message.getType()) {
                case KICK_USER:
                    JOptionPane.showMessageDialog(ChatClient.this, message.getContent());
                    loginManager.disconnect();
                    break;
                case USER_LIST_UPDATE:
                    updateUserList(message.getContent());
                    break;
                case GROUP_CHAT:
                    handleGroupMessage(message);
                    break;
                case PRIVATE_CHAT:
                    handlePrivateMessage(message);
                    break;
                case FILE_TRANSFER:
                    fileTransferManager.handleFileTransfer(message);
                    break;
                case GROUP_FILE:
                    fileTransferManager.handleGroupFile(message);
                    break;
                case GROUP_MEMBER_LIST:
                    updateGroupMemberList(message);
                    break;
                case SUBGROUP_INVITE:
                    handleSubgroupInvite(message);
                    break;
                case SUBGROUP_ACCEPT:
                    handleSubgroupAccept(message);
                    break;
                case SUBGROUP_CHAT:
                    handleSubgroupChat(message);
                    break;
                case IP_UPDATE:
                    handleIpUpdate(message);
                    break;
                case IMAGE:
                    handleImageMessage(message);
                    break;
                case IMAGE_DOWNLOAD_RESPONSE:
                    handleImageDownloadResponse(message);
                    break;
            }
        }

        private void updateUserList(String userListStr) {
            userListModel.clear();
            if (!userListStr.isEmpty()) {
                String[] users = userListStr.split(",");
                for (String user : users) {
                    userListModel.addElement(user);
                }
            }
        }

        private void handleGroupMessage(Message message) {
            String group = message.getGroup();
            ChatPanel panel = chatPanels.computeIfAbsent("group_" + group, k -> {
                ChatPanel newPanel = new ChatPanel(group, true);
                chatTabs.addTab("群聊: " + group, newPanel);
                openWindowCount++;
                return newPanel;
            });
            panel.displayMessage(message);

            if (!groupListModel.contains(group)) {
                groupListModel.addElement(group);
            }
        }

        private void updateGroupMemberList(Message message) {
            String group = message.getGroup();
            if (group != null) {
                groupMembers.put(group, new HashSet<>(message.getMemberList()));
                memberListModel.clear();
                for (String member : message.getMemberList()) {
                    memberListModel.addElement(member);
                }
            }
        }

        private void handleSubgroupInvite(Message message) {
            String group = message.getGroup();
            String groupUserKey = group + ":" + username;

            if (userGroupSubgroup.containsKey(groupUserKey)) {
                JOptionPane.showMessageDialog(ChatClient.this, "您已在本群加入其他小组，无法接受新邀请");
                sendSubgroupResponse(message.getSender(), message.getSubgroupId(), false);
                return;
            }

            int option = JOptionPane.showConfirmDialog(ChatClient.this,
                    message.getSender() + " 邀请您加入"+group+"中的小组 " + message.getSubgroupId() + "\n是否接受？",
                    "小组邀请", JOptionPane.YES_NO_OPTION);

            if (option == JOptionPane.YES_OPTION) {
                currentSubgroupId = message.getSubgroupId();
                userSubgroups.put(username, currentSubgroupId);
                userGroupSubgroup.put(groupUserKey, message.getSubgroupId());
                subgroupToGroupMap.put(message.getSubgroupId(), message.getGroup());
                sendSubgroupResponse(message.getSender(), message.getSubgroupId(), true);
                memberListManager.openSubgroupChat(message.getSubgroupId());
            } else {
                sendSubgroupResponse(message.getSender(), message.getSubgroupId(), false);
            }
        }

        private void sendSubgroupResponse(String sender, String subgroupId, boolean accepted) {
            try {
                Message response = new Message(
                        accepted ? Message.Type.SUBGROUP_ACCEPT : Message.Type.SUBGROUP_REJECT,
                        username, accepted ? "已接受小组邀请" : "已拒绝小组邀请");
                response.setReceiver(sender);
                response.setSubgroupId(subgroupId);
                output.writeObject(response);
            } catch (IOException ex) {
                JOptionPane.showMessageDialog(ChatClient.this, "响应发送失败: " + ex.getMessage());
            }
        }

        private void handleSubgroupAccept(Message message) {
            String subgroupId = message.getSubgroupId();
            subgroupMembers.computeIfAbsent(subgroupId, k -> new HashSet<>()).add(message.getSender());

            String tabId = "subgroup_" + subgroupId;
            ChatPanel panel = chatPanels.get(tabId);
            if (panel != null) {
                panel.displayMessage(new Message(Message.Type.SUBGROUP_CHAT, "系统",
                        message.getSender() + " 已加入小组"));
            }
        }

        private void handleSubgroupChat(Message message) {
            String subgroupId = message.getSubgroupId();
            if (subgroupId.equals(currentSubgroupId)) {
                String tabId = "subgroup_" + subgroupId;
                ChatPanel panel = chatPanels.get(tabId);
                if (panel != null) {
                    panel.displayMessage(message);
                }
            }
        }

        private void handleIpUpdate(Message message) {
            String user = message.getSender();
            String ip = message.getIpAddress();
            int port = message.getVoicePort();

            if (user != null && ip != null&&port>0) {
                VoiceChatManager.updateUserIP(user, ip, port);

                if (isVoiceActive && user.equals(currentVoiceTarget)) {
                    new Thread(() -> {
                        try {
                            Thread.sleep(500);
                            VoiceChatManager.updateUserPort(user, port);
                            VoiceChatManager.startVoiceChat(currentVoiceTarget);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }).start();
                }
            }
        }

        private void handlePrivateMessage(Message message) {
            String otherUser = message.getSender().equals(username) ?
                    message.getReceiver() : message.getSender();
            String chatId = "private_" + otherUser;

            ChatPanel panel = chatPanels.get(chatId);
            if (panel == null) {
                ChatClient.this.openPrivateChat(otherUser);
                panel = chatPanels.get(chatId);
            }

            if (panel != null) {
                panel.displayMessage(message);
            }

            if (message.getContent().contains("[语音邀请]") && isNewMessage(message.getTimestamp())) {
                if (message.getSender().equals(username)) {
                    return;
                }

                int option = JOptionPane.showConfirmDialog(ChatClient.this,
                        message.getSender() + " 邀请您进行语音聊天，是否接受？",
                        "语音邀请", JOptionPane.YES_NO_OPTION);

                if (option == JOptionPane.YES_OPTION) {
                    currentVoiceTarget = message.getSender();
                    isVoiceActive = true;

                    VoiceChatManager.initialize(username);

                    new Thread(() -> {
                        try {
                            Thread.sleep(500);
                            if (VoiceChatManager.startVoiceChat(currentVoiceTarget)) {
                                SwingUtilities.invokeLater(() -> {
                                    voiceStatusLabel.setText("语音状态: 与 " + currentVoiceTarget + " 通话中");
                                    voiceControlDialog.setVisible(true);
                                });

                                try {
                                    Message acceptMsg = new Message(Message.Type.PRIVATE_CHAT,
                                            username, "[语音接受] 已接受语音聊天");
                                    acceptMsg.setReceiver(currentVoiceTarget);
                                    output.writeObject(acceptMsg);
                                } catch (IOException e) {
                                    e.printStackTrace();
                                }
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }).start();
                }
            }

            if (message.getContent().contains("[会议邀请]")&&
                    isNewMessage(message.getTimestamp())) {
                String roomId = message.getContent().substring(
                        message.getContent().indexOf("房间ID: ") + 6);

                int option = JOptionPane.showConfirmDialog(ChatClient.this,
                        message.getSender() + " 邀请您加入语音会议，房间ID: " + roomId + "\n是否加入？",
                        "会议邀请", JOptionPane.YES_NO_OPTION);

                if (option == JOptionPane.YES_OPTION) {
                    isVoiceActive = true;

                    VoiceChatManager.initialize(username);
                    if (VoiceChatManager.joinConferenceRoom(roomId, username)) {
                        voiceStatusLabel.setText("语音状态: 会议中 (房间ID: " + roomId + ")");
                        voiceControlDialog.setVisible(true);
                    }
                }
            }
        }

        private boolean isNewMessage(String messageTimestamp) {
            if (lastLoginTime.isEmpty()) return true;
            long msgTime = timestampToMillis(messageTimestamp);
            long loginTime = timestampToMillis(lastLoginTime);
            return msgTime >= loginTime;
        }

        private long timestampToMillis(String timestamp) {
            try {
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                LocalDateTime dateTime = LocalDateTime.parse(timestamp, formatter);
                return dateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
            } catch (Exception e) {
                e.printStackTrace();
                return 0;
            }
        }

        private void handleImageMessage(Message message) {
            if (message.getGroup() != null) {
                handleGroupMessage(message);
            } else if (message.getReceiver() != null) {
                handlePrivateMessage(message);
            } else if (message.getSubgroupId() != null) {
                handleSubgroupChat(message);
            }
        }

        private void handleImageDownloadResponse(Message message) {
            if (message.getFileName() != null && message.getFileData() != null) {
                File imgDir = new File("chat_history/images/");
                imgDir.mkdirs();
                File imgFile = new File(imgDir, message.getFileName());
                try (FileOutputStream fos = new FileOutputStream(imgFile)) {
                    fos.write(message.getFileData());
                } catch (IOException e) {
                    JOptionPane.showMessageDialog(ChatClient.this, "图片保存失败: " + e.getMessage());
                }
                for (ChatPanel panel : chatPanels.values()) {
                    panel.repaint();
                }
            }
        }
    }

    // ================== 聊天面板 ==================
    private class ChatPanel extends JPanel {
        private JTextField inputField;
        private String chatTarget;
        private boolean isGroup;
        private boolean isSubgroup;
        private JPanel chatDisplayPanel;

        public ChatPanel(String target, boolean isGroup) {
            this(target, isGroup, false);
        }

        public ChatPanel(String target, boolean isGroup, boolean isSubgroup) {
            this.chatTarget = target;
            this.isGroup = isGroup;
            this.isSubgroup = isSubgroup;
            initializePanel();
        }

        public String getChatTarget() {
            return chatTarget;
        }

        public boolean isGroup() {
            return isGroup;
        }

        private void initializePanel() {
            setLayout(new BorderLayout());
            chatDisplayPanel = new JPanel();
            chatDisplayPanel.setLayout(new BoxLayout(chatDisplayPanel, BoxLayout.Y_AXIS));
            JScrollPane scrollPane = new JScrollPane(chatDisplayPanel);
            scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);

            JPanel inputPanel = new JPanel(new BorderLayout());
            inputField = new JTextField();
            JButton sendBtn = new JButton("发送");
            JButton fileBtn = new JButton("发送文件");
            JButton imageBtn = new JButton("发送图片");

            inputField.addActionListener(e -> sendMessage());
            sendBtn.addActionListener(e -> sendMessage());
            fileBtn.addActionListener(e -> sendFile());
            imageBtn.addActionListener(e -> sendImage());

            JPanel buttonPanel = new JPanel(new FlowLayout());
            buttonPanel.add(sendBtn);
            if (!isGroup) {
                buttonPanel.add(fileBtn);
            }
            buttonPanel.add(imageBtn);

            inputPanel.add(inputField, BorderLayout.CENTER);
            inputPanel.add(buttonPanel, BorderLayout.EAST);
            add(scrollPane, BorderLayout.CENTER);
            add(inputPanel, BorderLayout.SOUTH);

            String welcomeMsg;
            if (isSubgroup) {
                welcomeMsg = "欢迎加入小组: " + chatTarget + "\n发送消息开始小组讨论吧！\n";
            } else if (isGroup) {
                welcomeMsg = "欢迎加入群组: " + chatTarget + "\n发送消息开始聊天吧！\n";
            } else {
                welcomeMsg = "与 " + chatTarget + " 的私聊\n发送消息开始聊天吧！\n";
            }
            appendText(welcomeMsg);
        }

        private void appendText(String text) {
            JTextArea area = new JTextArea(text);
            area.setEditable(false);
            area.setLineWrap(true);
            area.setWrapStyleWord(true);
            area.setFont(new Font("宋体", Font.PLAIN, 12));
            area.setBackground(chatDisplayPanel.getBackground());
            chatDisplayPanel.add(area);
            chatDisplayPanel.revalidate();
            chatDisplayPanel.repaint();
        }

        private void appendImage(byte[] imageData) {
            try {
                ImageIcon icon = new ImageIcon(imageData);
                int thumbWidth = 100;
                int thumbHeight = 100;
                Image img = icon.getImage();
                Image scaledImg = img.getScaledInstance(thumbWidth, thumbHeight, Image.SCALE_SMOOTH);
                ImageIcon thumbIcon = new ImageIcon(scaledImg);
                JLabel label = new JLabel(thumbIcon);
                label.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0));
                label.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
                label.addMouseListener(new java.awt.event.MouseAdapter() {
                    @Override
                    public void mouseClicked(java.awt.event.MouseEvent e) {
                        JDialog dialog = new JDialog((JFrame) SwingUtilities.getWindowAncestor(label), "查看大图", true);
                        JLabel bigImgLabel = new JLabel(new ImageIcon(imageData));
                        JScrollPane scrollPane = new JScrollPane(bigImgLabel);
                        dialog.getContentPane().add(scrollPane);
                        dialog.setSize(600, 600);
                        dialog.setLocationRelativeTo(label);
                        dialog.setVisible(true);
                    }
                });
                JPanel leftPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
                leftPanel.setOpaque(false);
                leftPanel.add(label);
                chatDisplayPanel.add(leftPanel);
                chatDisplayPanel.revalidate();
                chatDisplayPanel.repaint();
            } catch (Exception e) {
                appendText("[图片显示失败]");
            }
        }

        private void sendMessage() {
            String content = inputField.getText().trim();
            if (!content.isEmpty()) {
                try {
                    Message message;
                    if (isSubgroup) {
                        message = new Message(Message.Type.SUBGROUP_CHAT, username, content);
                        message.setSubgroupId(chatTarget);
                    } else if (isGroup) {
                        message = new Message(Message.Type.GROUP_CHAT, username, content);
                        message.setGroup(chatTarget);
                    } else {
                        message = new Message(Message.Type.PRIVATE_CHAT, username, content);
                        message.setReceiver(chatTarget);
                    }
                    output.writeObject(message);
                    inputField.setText("");
                } catch (IOException e) {
                    JOptionPane.showMessageDialog(ChatClient.this, "发送失败: " + e.getMessage());
                }
            }
        }

        private void sendFile() {
            if (!isGroup) {
                JFileChooser fileChooser = new JFileChooser();
                if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
                    File file = fileChooser.getSelectedFile();
                    if (file.length() > 10 * 1024 * 1024) {
                        JOptionPane.showMessageDialog(ChatClient.this, "文件大小不能超过10MB");
                        return;
                    }
                    try {
                        byte[] fileData = fileTransferManager.readFileData(file);
                        Message fileMsg = new Message(Message.Type.FILE_TRANSFER, username, "发送了文件");
                        fileMsg.setReceiver(chatTarget);
                        fileMsg.setFileName(file.getName());
                        fileMsg.setFileData(fileData);
                        output.writeObject(fileMsg);
                        displayMessage(new Message(Message.Type.PRIVATE_CHAT, username,
                                "[文件] " + file.getName() + " (" + (file.length() / 1024) + " KB)"));
                    } catch (IOException e) {
                        JOptionPane.showMessageDialog(ChatClient.this, "文件发送失败: " + e.getMessage());
                    }
                }
            }
        }

        private void sendImage() {
            JFileChooser fileChooser = new JFileChooser();
            fileChooser.setFileFilter(new javax.swing.filechooser.FileNameExtensionFilter("图片文件", "jpg", "jpeg", "png", "gif", "bmp"));
            if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
                File file = fileChooser.getSelectedFile();
                if (file.length() > 5 * 1024 * 1024) {
                    JOptionPane.showMessageDialog(ChatClient.this, "图片大小不能超过5MB");
                    return;
                }
                try {
                    byte[] imageData = fileTransferManager.readFileData(file);
                    Message imageMsg = new Message(Message.Type.IMAGE, username, "[图片]");
                    if (isSubgroup) {
                        imageMsg.setSubgroupId(chatTarget);
                    } else if (isGroup) {
                        imageMsg.setGroup(chatTarget);
                    } else {
                        imageMsg.setReceiver(chatTarget);
                    }
                    imageMsg.setFileName(file.getName());
                    imageMsg.setFileData(imageData);
                    output.writeObject(imageMsg);
                } catch (IOException e) {
                    JOptionPane.showMessageDialog(ChatClient.this, "图片发送失败: " + e.getMessage());
                }
            }
        }

        public void displayMessage(Message message) {
            if (message.getType() == Message.Type.IMAGE) {
                String info = String.format("[%s] %s: [图片] %s",
                        message.getTimestamp(), message.getSender(), message.getFileName());
                appendText(info);
                byte[] imageData = message.getFileData();
                if (imageData != null) {
                    appendImage(imageData);
                } else if (message.getFileName() != null) {
                    File imgFile = new File("chat_history/images/" + message.getFileName());
                    if (imgFile.exists()) {
                        try (FileInputStream fis = new FileInputStream(imgFile)) {
                            byte[] data = new byte[(int) imgFile.length()];
                            fis.read(data);
                            appendImage(data);
                        } catch (Exception e) {
                            appendText("[图片加载失败]");
                        }
                    } else {
                        try {
                            Message req = new Message(Message.Type.IMAGE_DOWNLOAD_REQUEST, username, message.getFileName());
                            output.writeObject(req);
                        } catch (IOException e) {
                            appendText("[图片请求失败]");
                        }
                        appendText("[图片正在下载]");
                    }
                }
                return;
            }
            if (message.getContent().equals("加入了群组") && message.getSender().equals(username)) {
                return;
            }
            String displayText = String.format("[%s] %s: %s\n",
                    message.getTimestamp(), message.getSender(), message.getContent());
            appendText(displayText);
        }
    }

    // ================== 主要面板管理+辅助方法 ==================
    private class MainPanelManager {
        public JPanel createMainPanel() {
            JPanel panel = new JPanel(new BorderLayout());

            userListModel = new DefaultListModel<>();
            userList = new JList<>(userListModel);
            userList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
            userList.addMouseListener(new java.awt.event.MouseAdapter() {
                @Override
                public void mouseClicked(java.awt.event.MouseEvent e) {
                    if (e.getClickCount() == 2) {
                        String selectedUser = userList.getSelectedValue();
                        if (selectedUser != null && !selectedUser.equals(username)) {
                            openPrivateChat(selectedUser);
                        }
                    }
                }
            });

            groupListModel = new DefaultListModel<>();
            groupList = new JList<>(groupListModel);
            groupList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
            groupList.addMouseListener(new java.awt.event.MouseAdapter() {
                @Override
                public void mouseClicked(java.awt.event.MouseEvent e) {
                    if (e.getClickCount() == 2) {
                        String selectedGroup = groupList.getSelectedValue();
                        try {
                            Message request = new Message(Message.Type.GROUP_MEMBER_REQUEST, username, "");
                            request.setGroup(selectedGroup);
                            output.writeObject(request);
                        } catch (IOException ex) {
                            ex.printStackTrace();
                        }
                        if (selectedGroup != null) {
                            groupManager.openGroupChat(selectedGroup);
                        }
                    }
                }
            });

            JSplitPane userGroupSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
                    new JScrollPane(userList), new JScrollPane(groupList));
            userGroupSplitPane.setDividerLocation(200);
            userGroupSplitPane.setPreferredSize(new Dimension(180, 0));
            userGroupSplitPane.setBorder(new TitledBorder("在线用户 (双击私聊) / 群聊列表 (双击打开)"));

            chatTabs = new JTabbedPane();
            chatTabs.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);

            JPanel groupPanel = groupManager.createGroupPanel();

            panel.add(userGroupSplitPane, BorderLayout.WEST);
            panel.add(chatTabs, BorderLayout.CENTER);
            panel.add(groupPanel, BorderLayout.SOUTH);

            return panel;
        }
    }

    private void receiveMessages() {
        try {
            while (true) {
                Message message = (Message) input.readObject();
                SwingUtilities.invokeLater(() -> messageHandler.handleMessage(message));
            }
        } catch (Exception e) {
            SwingUtilities.invokeLater(() -> {
                String errorMsg = e.getMessage();
                if ((errorMsg == null || !errorMsg.contains("Socket closed")) && socket != null) {
                    JOptionPane.showMessageDialog(this, "连接断开: " +
                            (errorMsg != null ? errorMsg : e.getClass().getSimpleName()));
                }
                loginManager.disconnect();
            });
        }
    }

    private void openPrivateChat(String targetUser) {
        if (openWindowCount >= MAX_WINDOWS) {
            JOptionPane.showMessageDialog(ChatClient.this, "最多只能打开" + MAX_WINDOWS + "个聊天窗口");
            return;
        }

        String tabId = "private_" + targetUser;
        if (!chatPanels.containsKey(tabId)) {
            ChatPanel panel = new ChatPanel(targetUser, false);
            chatPanels.put(tabId, panel);
            chatTabs.addTab("私:" + targetUser, panel);

            int index = chatTabs.getTabCount() - 1;
            chatTabs.setTabComponentAt(index, createTabComponent("私:" + targetUser, tabId));

            openWindowCount++;
        }

        for (int i = 0; i < chatTabs.getTabCount(); i++) {
            Component tabComponent = chatTabs.getTabComponentAt(i);
            if (tabComponent instanceof JPanel) {
                JLabel label = (JLabel) ((JPanel) tabComponent).getComponent(0);
                if (label.getText().equals("私:" + targetUser)) {
                    chatTabs.setSelectedIndex(i);
                    break;
                }
            }
        }
    }

    private JPanel createTabComponent(String title, String tabId) {
        JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
        panel.setOpaque(false);

        JLabel label = new JLabel(title);
        JButton closeBtn = new JButton("×");
        closeBtn.setPreferredSize(new Dimension(17, 17));
        closeBtn.setMargin(new Insets(0, 0, 0, 0));
        closeBtn.setFont(new Font("Dialog", Font.PLAIN, 12));
        closeBtn.addActionListener(e -> closeTab(tabId));

        panel.add(label);
        panel.add(Box.createHorizontalStrut(5));
        panel.add(closeBtn);

        return panel;
    }

    private void closeTab(String tabId) {
        ChatPanel panel = chatPanels.remove(tabId);
        if (panel != null) {
            for (int i = 0; i < chatTabs.getTabCount(); i++) {
                if (chatTabs.getComponentAt(i) == panel) {
                    chatTabs.removeTabAt(i);
                    openWindowCount--;
                    break;
                }
            }
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } catch (Exception e) {
                e.printStackTrace();
            }
            new ChatClient().setVisible(true);
        });
    }
}